﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace CoolCode.Web.UI.WebControls
{
    [ToolboxBitmap(typeof(Pager), "CoolCode.Web.UI.WebControls.Pager.ico"), ToolboxData("<{0}:Pager runat=server></{0}:Pager>")]
    public class Pager : Control, IPager, IPagingBinder, IPostBackEventHandler
    {
        #region Fields

        private int? _pageIndex;
        private const int DefaultPageSize = 10;

        #endregion

        #region Private Methods

        public string GetProperty(string name)
        {
            return ViewState[name] == null ? null : ViewState[name].ToString();
        }

        public T GetProperty<T>(string name)
        {
            return GetProperty<T>(name, default(T));
        }

        public T GetProperty<T>(string name, T defaultValue)
        {
            return ViewState[name] == null ? defaultValue : (T)ViewState[name];
        }

        public void SetProperty(string name, object value)
        {
            ViewState[name] = value;
        }

        public void WriteStyle(string resourceName)
        {
            WriteStyle(resourceName, true);
        }

        public void WriteStyle(string resourceName, bool onlyOnce)
        {
            string cssUrl = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), resourceName);
            if (!onlyOnce || !ContainsLink(cssUrl))
            {
                HtmlGenericControl cssLink = new HtmlGenericControl("LINK");
                cssLink.Attributes["rel"] = "stylesheet";
                cssLink.Attributes["type"] = "text/css";
                cssLink.Attributes["href"] = cssUrl;
                this.Page.Header.Controls.Add(cssLink);
            }
        }

        public bool ContainsLink(string url)
        {
            foreach (Control ctl in this.Page.Header.Controls)
            {
                if (ctl is HtmlGenericControl)
                {
                    HtmlGenericControl cssLink = (HtmlGenericControl)ctl;
                    if (cssLink.Attributes["href"] == url)
                        return true;
                }
            }
            return false;
        }

        private static int ToInt32(object obj, int defaultValue)
        {
            int result = 0;
            if ((obj != null) && (obj != DBNull.Value))
            {
                if (!int.TryParse(obj.ToString(), out result))
                {
                    result = defaultValue;
                }
            }
            return result;
        }

        private string clientOnClickReference(int pageIndex)
        {
            string result;
            if (!this.PagingOnPost)
            {
                result = string.Format("javascript:cc_PageLink({0},'{1}','{2}',{3});", pageIndex, this.ParameterName,
                    this.OnClientClick, this.IsContinue.ToString().ToLower());
            }
            else
            {
                result = "javascript:" + Page.ClientScript.GetPostBackEventReference(this, pageIndex.ToString());
                //  result = string.Format( "javascript:___doPostBack('{0}','{1}');" , this.UniqueID ,  pageIndex  );
            }
            return result;
        }

        private void renderSummaryInfo(HtmlTextWriter output)
        {
            //output.Write("<span class=\"{0}\">页次：<b>{1}</b>/<b>{2}</b>页 每页记录：<b>{3}</b>条 记录总数：<b>{4}</b> </span>",
            //    this.SummaryInfoCss, this.PageIndex + 1, this.PageCount, this.PageSize, this.TotalRecords);
            string summaryInfo = SummaryInfoTemplate
                .Replace("{PageIndex}", (this.PageIndex + 1).ToString())
                .Replace("{PageCount}", this.PageCount.ToString())
                .Replace("{PageSize}", this.PageSize.ToString())
                .Replace("{TotalRecords}", this.TotalRecords.ToString());
            string summaryHtml = string.Format("<span class=\"{0}\">{1}</span>",
                this.SummaryInfoCss, summaryInfo);
            output.Write(summaryHtml);
        }

        private void renderPageLink(HtmlTextWriter output, int pageIndex, string displayText, bool disabled)
        {
            if (!disabled)
            {
                output.Write("<a href=\"{0}\">{1}</a>", clientOnClickReference(pageIndex), displayText);
            }
            else
            {
                output.Write("<span class=\"disabled\">{0}</span>", displayText);
            }
        }

        private void renderPageLink(HtmlTextWriter output, int pageIndex, bool isCurrentPage)
        {
            string displayText = (pageIndex + 1).ToString();
            if (!isCurrentPage)
            {
                renderPageLink(output, pageIndex, displayText, false);
            }
            else
            {
                output.Write("<span class=\"current\">{0}</span>", displayText);
            }
        }

        private void renderNumericPages(HtmlTextWriter output)
        {
            const int MiddlePageIndex = 5;
            const int PageRange = MiddlePageIndex * 2;
            Func<int, int> clipIfMore = value =>
            {
                if (value > this.PageCount - 1)
                {
                    return this.PageCount - 1;
                }
                return value;
            };

            Func<int, int> clipIfLess = value =>
            {
                if (value < 0)
                {
                    return 0;
                }
                return value;
            };

            int maxpage = clipIfMore(this.PageIndex + MiddlePageIndex);
            int minpage = clipIfLess(this.PageIndex - MiddlePageIndex + 1);
            if (maxpage - minpage + 1 < PageRange)
            {
                if (minpage > 0)
                {
                    minpage = clipIfLess(maxpage - PageRange + 1);
                }
                if (maxpage < this.PageCount - 1)
                {
                    maxpage = clipIfMore(minpage + PageRange - 1);
                }
            }

            if (minpage > 0)
            {
                output.Write("...");
            }
            for (int i = minpage; i <= maxpage; i++)
            {
                bool isCurrentPage = (i == this.PageIndex);
                renderPageLink(output, i, isCurrentPage);
            }
            if (maxpage < this.PageCount - 1)
            {
                output.Write("...");
            }
        }

        protected string InputName
        {
            get
            {
                return "pageinput_" + this.UniqueID;// + this.ClientID;
            }
        }

        protected string ButtonName
        {
            get
            {
                return "pageSubmit_" + this.UniqueID; //+ this.ClientID;
            }
        }

        private void renderInput(HtmlTextWriter output)
        {
            string customScript = "var v =document.getElementById('" + InputName + "').value; " +
                "__doPostBack('" + this.UniqueID + "',v-1); return false;";

            string inputHtml = string.Concat(new object[] { "&nbsp;<input name=\""+ InputName , 
                        "\" id=\""+ InputName , "\" type=\"text\" class=\"", this.InputCss, "\" value='", 
                        this.PageIndex+1, "' onkeydown=\"" ,"if (event.keyCode == 13){", ButtonName  ,
                         ".onclick();return false;","}"   , "\" />" });

            string buttonHtml = "<a name=\"" + ButtonName + "\" href='#' class=\"" +
                    this.ButtonCss + "\" id=\"" + ButtonName + "\"  onclick=\"" +
               customScript + "\">" + this.ButtonText + " </a>&nbsp;";

            output.Write(inputHtml);
            output.Write(buttonHtml);
        }

        private void renderDesignHtml(HtmlTextWriter output)
        {
            string text = string.Concat(new object[] { " <div class=\"", this.CustomCss, "\" align=\"", this.Align, "\">" });

            text += " <span class=\"disabled\"> " + this.PreviousPageText + " </span><span class=\"current\">1</span>" +
                "<a href=\"\">2</a><a href=\"\">3</a><a href=\"\">4</a><a href=\"\">5</a>" +
                "<a href=\"\">6</a><a href=\"\">7</a>...<a href=\"\">199</a><a href=\"\">200</a>" +
                "<a href=\"\"> " + this.NextPageText + " </a>";

            if (this.InputVisible)
            {
                string tmpString = text + "&nbsp;<input name=\"pageinput\" type=\"text\" class=\"" + this.InputCss +
                      "\" id=\"pageinput\" />";
                text = tmpString + "<input name=\"pageSubmit\" type=\"button\" class=\"" + this.ButtonCss +
                    "\" id=\"pageSubmit\" value=\"" + this.ButtonText + "\" />";
            }

            if (this.SummaryInfoVisible)
            {
                text += "<span class=\"" + this.SummaryInfoCss + "\">页数：<b>1</b>/<b>17</b>&nbsp;| 总数：<b>200</b></span>";
            }
            output.Write(text);
        }

        #endregion

        public Pager()
        {
            this.PageSize = DefaultPageSize;
            //this.PagingOnPost = false;
            this.ParameterName = "page";
            this.FirstPageText = "<<";
            this.PreviousPageText = "<";
            this.NextPageText = ">";
            this.LastPageText = ">>";
            this.AutoRetrieveParam = true;
            this.Align = Position.center;
            this.ButtonText = "Go";
            this.ButtonCss = "pagebutton";
            this.InputCss = "pageinput";
            this.SummaryInfoCss = "pagecount";
            this.OnClientClick = string.Empty;
            this.Css = PagerStyle.manu;
            this.NumericPageVisible = true;
            this.InputVisible = true;
            this.SummaryInfoVisible = true;
            this.IsContinue = true;
            this.SummaryInfoTemplate = "页次：<b>{PageIndex}</b>/<b>{PageCount}</b>页 " +
                "每页记录：<b>{PageSize}</b>条 记录总数：<b>{TotalRecords}</b>";
        }


        #region Public Methods

        public PagedDataSource GetDataSource()
        {
            PagedDataSource _returnDataSource = new PagedDataSource();
            _returnDataSource.AllowPaging = true;
            _returnDataSource.DataSource = this.DataSource;
            _returnDataSource.PageSize = this.PageSize;
            _returnDataSource.CurrentPageIndex = this.PageIndex;
            this.TotalRecords = _returnDataSource.DataSourceCount;
            return _returnDataSource;
        }

        #endregion

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (!base.DesignMode)
            {
                this.Page.ClientScript.RegisterClientScriptResource(base.GetType(), "CoolCode.Web.UI.WebControls.Pager.js");
                WriteStyle("CoolCode.Web.UI.WebControls.Pager.css");
            }
        }

        /*重构Render方法 -  Bruce Oct 30，2009 */
        protected override void Render(HtmlTextWriter output)
        {
            if (!base.DesignMode)
            {
                output.AddAttribute(HtmlTextWriterAttribute.Class, this.CustomCss);
                output.AddAttribute(HtmlTextWriterAttribute.Align, this.Align.ToString());
                output.RenderBeginTag(HtmlTextWriterTag.Div);

                if (this.TotalRecords > 0)
                {
                    renderPageLink(output, 0, FirstPageText, !HasPreviousPage);
                    renderPageLink(output, PageIndex - 1, PreviousPageText, !HasPreviousPage);

                    //render numeric page
                    if (NumericPageVisible)
                    {
                        renderNumericPages(output);
                    }

                    renderPageLink(output, PageIndex + 1, NextPageText, !HasNextPage);
                    renderPageLink(output, PageCount - 1, LastPageText, !HasNextPage);

                    if (this.InputVisible)
                    {
                        renderInput(output);
                    }
                }

                if (this.SummaryInfoVisible)
                {
                    renderSummaryInfo(output);
                }

                output.RenderEndTag();
            }
            else
            {//For Design Mode
                renderDesignHtml(output);
            }
        }

        #region Old Methods
        /*
        protected override void Render(HtmlTextWriter output)
        {
            string tmpString;
            TextBuilder text = string.Empty;
            string cssName = string.Empty;
            if (this.CustomCss != "")
            {
                cssName = this.CustomCss;
            }
            else
            {
                cssName = this.Css.ToString();
            }
            if (!base.DesignMode)
            {
                string summaryHtml = string.Empty;
                if (this.TextVisible)
                {
                    renderSummaryInfo(output);
                }

                if (this.TotalRecords > 0)
                {
                    string firstPageHtml = "<a href=\"" + clientOnClickReference(0) + "\">1</a>...";
                    string prevPageHtml = string.Concat(new object[] { "<a href=\"" + clientOnClickReference(this.PageIndex - 1) + "\"> ", this.PrevText, " </a>" });
                    string prevPageHtml_disable = "<span class=\"disabled\"> " + this.PrevText + " </span>";
                    string nextPageHtml = string.Concat(new object[] { "<a href=\"" + clientOnClickReference(this.PageIndex + 1) + "\"> ", this.NextText, " </a>" });
                    string nextPageHtml_disable = "<span class=\"disabled\"> " + this.NextText + " </span>";
                    string lastPageHtml = string.Concat(new object[] { "...<a href=\"" + clientOnClickReference(this.PageCount - 1) + "\">", this.PageCount, "</a>" });

                    string inputHtml = string.Empty;
                    if (this.InputVisible)
                    {
                        string customScript = "var v =document.getElementById('pageinput_" + this.UniqueID + "').value; __doPostBack('" + this.UniqueID + "',v-1); return false;";
                        tmpString = string.Concat(new object[] { "&nbsp;<input name=\"pageinput_", this.UniqueID, 
                        "\" type=\"text\" class=\"", this.InputCss, "\" id=\"pageinput_", this.UniqueID, "\" value='", 
                        this.PageIndex+1, "' onkeydown=\"" ,"if (event.keyCode == 13){pageSubmit_", this.UniqueID ,
                         ".onclick();return false;","}"   , "\" />" });

                        inputHtml = tmpString + "<a name=\"pageSubmit_" + this.UniqueID + "\" href='#' class=\"" +
                               this.ButtonCss + "\" id=\"_" + this.UniqueID + "\"  onclick=\"" +
                          customScript + "\">" + this.ButtonText + " </a>&nbsp;";
                    }

                    text += this.HasPreviousPage ? prevPageHtml : prevPageHtml_disable;
                    const int MiddlePageIndex = 5;
                    if (this.PageIndex >= MiddlePageIndex)
                    {
                        text += firstPageHtml;
                    }

                    int maxpage = this.PageIndex + MiddlePageIndex;
                    if (maxpage > this.PageCount - 1)
                    {
                        maxpage = this.PageCount - 1;
                    }

                    int minpage = this.PageIndex - MiddlePageIndex + 1;
                    if (minpage < 0)
                    {
                        minpage = 0;
                    }

                    for (int i = minpage; i <= maxpage; i++)
                    {
                        if (i >= 0)
                        {
                            if (i == this.PageIndex)
                            {
                                text += this.aTag_cur(i);
                            }
                            else
                            {
                                text += this.aTag(i);
                            }
                        }
                    }
                    if ((this.PageIndex + MiddlePageIndex) < this.PageCount - 1)
                    {
                        text += lastPageHtml;
                    }

                    text += HasNextPage ? nextPageHtml : nextPageHtml_disable;
                    text += inputHtml;
                }//end if (this.TotalRecords >0)

                text += summaryHtml;

                text = string.Concat(new object[] { "<div class='", cssName, "' align=\"", this.Align, "\">", text, "</div>" });
                output.Write(text);
            }
            else
            {//For Design Mode
                text = string.Concat(new object[] { " <div class=\"", cssName, "\" align=\"", this.Align, "\">" });

                text += " <span class=\"disabled\"> " + this.PrevText + " </span><span class=\"current\">1</span>" +
                    "<a href=\"\">2</a><a href=\"\">3</a><a href=\"\">4</a><a href=\"\">5</a>" +
                    "<a href=\"\">6</a><a href=\"\">7</a>...<a href=\"\">199</a><a href=\"\">200</a>" +
                    "<a href=\"\"> " + this.NextText + " </a>";

                if (this.InputVisible)
                {
                    tmpString = text + "&nbsp;<input name=\"pageinput\" type=\"text\" class=\"" + this.InputCss +
                        "\" id=\"pageinput\" />";
                    text = tmpString + "<input name=\"pageSubmit\" type=\"button\" class=\"" + this.ButtonCss +
                        "\" id=\"pageSubmit\" value=\"" + this.ButtonText + "\" />";
                }

                if (this.TextVisible)
                {
                    text += "<span class=\"" + this.TextCss + "\">页数：<b>1</b>/<b>17</b>&nbsp;| 总数：<b>200</b></span>";
                }
                output.Write(text);
            }
        }*/
        #endregion

        #region Properties

        [Description("对齐方式"), Category("常用重要参数")]
        public Position Align
        {
            get
            {
                return GetProperty<Position>("Align");
            }
            set
            {
                SetProperty("Align", value);
            }
        }

        [Description("系统自带的css样式,当CustomCss为空时有效."), Category("常用重要参数")]
        [Bindable(true)]
        public PagerStyle Css
        {
            get
            {
                return GetProperty<PagerStyle>("Css");
            }
            set
            {
                SetProperty("Css", value);
            }
        }

        [Description("是否自动获取当前页"), Category("参数控制")]
        public bool AutoRetrieveParam
        {
            get
            {
                return GetProperty<bool>("AutoRetrieveParam");
            }
            set
            {
                SetProperty("AutoRetrieveParam", value);
            }
        }

        [Category("文字"), Description("按钮文字")]
        public string ButtonText
        {
            get
            {
                return GetProperty("ButtonText");
            }
            set
            {
                SetProperty("ButtonText", value);
            }
        }

        [Description("按钮css样式"), Category("CSS样式")]
        public string ButtonCss
        {
            get
            {
                return GetProperty("ButtonCss");
            }
            set
            {
                SetProperty("ButtonCss", value);
            }
        }

        [Description("跳转链接时执行的客户端函数"), Category("客户端控制")]
        public string OnClientClick
        {
            get
            {
                return GetProperty("OnClientClick");
            }
            set
            {
                SetProperty("OnClientClick", value);
            }
        }

        [Description("总记录数"), Category("常用重要参数")]
        public int TotalRecords
        {
            get
            {
                return GetProperty("TotalRecords", 0);
            }
            set
            {
                SetProperty("TotalRecords", value);
            }
        }

        [Category("CSS样式"), Description("分页部分css样式")]
        public string CustomCss
        {
            get
            {
                return GetProperty("CustomCss", this.Css.ToString());
            }
            set
            {
                SetProperty("CustomCss", value);
            }
        }

        [Browsable(false), Category("常用重要参数"), Description("当前页")]
        public int PageIndex
        {
            get
            {
                if (!_pageIndex.HasValue)
                {
                    if (this.PagingOnPost)
                    {
                        _pageIndex = this.InputVisible ?
                            ToInt32(HttpContext.Current.Request.Form[InputName], 0) - 1 :
                           GetProperty<int>("PageIndex");
                    }
                    else
                    {
                        if (this.AutoRetrieveParam)
                        {
                            _pageIndex = ToInt32(HttpContext.Current.Request.QueryString[this.ParameterName], 0);
                        }
                    }
                }
                if (_pageIndex > this.PageCount - 1)
                {
                    _pageIndex = this.PageCount - 1;
                }
                if (_pageIndex < 0)
                {
                    _pageIndex = 0;
                }
                return _pageIndex.GetValueOrDefault(0);
            }
            set
            {
                _pageIndex = value;
                if (this.PagingOnPost && !this.InputVisible)
                {
                    SetProperty("PageIndex", value);
                }
            }
        }

        [Browsable(false)]
        public bool HasPreviousPage
        {
            get
            {
                return (PageIndex > 0);
            }
        }

        [Browsable(false)]
        public bool HasNextPage
        {
            get
            {
                return (PageIndex + 1 < PageCount);
            }
        }

        [Browsable(false)]
        public int PageCount
        {
            get
            {
                return (int)Math.Ceiling(TotalRecords / (double)PageSize);
            }
        }

        [Description("每页大小"), Category("常用重要参数")]
        public int PageSize
        {
            get
            {
                return GetProperty("PageSize", 10);
            }
            set
            {
                SetProperty("PageSize", value);
            }
        }

        [Description("记录集"), Category("数据绑定区")]
        public IEnumerable DataSource { get; set; }

        [Description("输入框css样式"), Category("CSS样式")]
        public string InputCss
        {
            get
            {
                return GetProperty("InputCss");
            }
            set
            {
                SetProperty("InputCss", value);
            }
        }

        [Description("是否显示输入框"), Category("显隐控制")]
        public bool InputVisible
        {
            get
            {
                return GetProperty<bool>("InputVisible");
            }
            set
            {
                SetProperty("InputVisible", value);
            }
        }

        [Description("是否显示数字分页"), Category("显隐控制")]
        public bool NumericPageVisible
        {
            get
            {
                return GetProperty<bool>("NumericPageVisible");
            }
            set
            {
                SetProperty("NumericPageVisible", value);
            }
        }

        /// <summary>
        /// 执行客户端函数时是否继续执行分页功能
        /// </summary>
        [Category("客户端控制"), Description("执行客户端函数时是否继续执行分页功能")]
        public bool IsContinue
        {
            get
            {
                return GetProperty<bool>("IsContinue");
            }
            set
            {
                SetProperty("IsContinue", value);
            }
        }

        [Description("参数名称"), Category("参数控制")]
        public string ParameterName
        {
            get
            {
                return GetProperty("ParameterName");
            }
            set
            {
                SetProperty("ParameterName", value);
            }
        }

        [Category("文字"), Description("第一页的文字")]
        public string FirstPageText
        {
            get
            {
                return GetProperty("FirstPageText");
            }
            set
            {
                SetProperty("FirstPageText", value);
            }
        }

        [Category("文字"), Description("最后一页的文字")]
        public string LastPageText
        {
            get
            {
                return GetProperty("LastPageText");
            }
            set
            {
                SetProperty("LastPageText", value);
            }
        }

        [Category("文字"), Description("上一页的文字")]
        public string PreviousPageText
        {
            get
            {
                return GetProperty("PreviousPageText");
            }
            set
            {
                SetProperty("PreviousPageText", value);
            }
        }

        [Category("文字"), Description("下一页的文字")]
        public string NextPageText
        {
            get
            {
                return GetProperty("NextPageText");
            }
            set
            {
                SetProperty("NextPageText", value);
            }
        }

        [Description("是否在Post时分页"), Category("其他")]
        public bool PagingOnPost
        {
            get
            {
                return GetProperty<bool>("PagingOnPost", (this.PageIndexChanging != null));
            }
            set
            {
                SetProperty("PagingOnPost", value);
            }
        }

        [Description("汇总信息css样式"), Category("CSS样式")]
        public string SummaryInfoCss
        {
            get
            {
                return GetProperty("SummaryInfoCss");
            }
            set
            {
                SetProperty("SummaryInfoCss", value);
            }
        }

        [Description("是否显示汇总信息"), Category("显隐控制")]
        public bool SummaryInfoVisible
        {
            get
            {
                return GetProperty<bool>("SummaryInfoVisible");
            }
            set
            {
                SetProperty("SummaryInfoVisible", value);
            }
        }

        [Description("汇总信息模板"), Category("CSS样式")]
        public string SummaryInfoTemplate
        {
            get
            {
                return GetProperty("SummaryInfoTemplate");
            }
            set
            {
                SetProperty("SummaryInfoTemplate", value);
            }
        }

        #endregion

        #region Events

        public event GridViewPageEventHandler PageIndexChanging;

        protected virtual void OnPageIndexChanging(GridViewPageEventArgs e)
        {
            if (this.PageIndexChanging != null)
            {
                this.PageIndexChanging(this, e);
            }
        }

        #endregion

        #region IPostBackEventHandler Members

        public void RaisePostBackEvent(string eventArgument)
        {
            int pageIndex;
            if (!int.TryParse(eventArgument, out pageIndex))
            {
                pageIndex = 0;
            }
            this.PageIndex = pageIndex;
            GridViewPageEventArgs e = new GridViewPageEventArgs(pageIndex);
            OnPageIndexChanging(e);
        }

        #endregion

        #region IPagingBinder Members

        public void Bind(IPaginatedList p)
        {
            this.PageIndex = p.PageIndex;
            this.PageSize = p.PageSize;
            this.TotalRecords = p.TotalRecords;
        }

        #endregion

    }

    public enum PagerStyle
    {
        quotes,
        grayr,
        digg,
        yahoo,
        yahoo2,
        meneame,
        flickr,
        sabrosus,
        scott,
        black,
        black2,
        black_red,
        yellow,
        jogger,
        starcraft2,
        tres,
        megas512,
        technorati,
        youtube,
        msdn,
        badoo,
        manu,
        green_black,
        viciao
    }

    public enum Position
    {
        left,
        center,
        right
    }
}
